﻿using System;
using System.Globalization;
using System.Reflection;
using UtilZ.Dotnet.Ex.Base;

namespace UtilZ.Dotnet.Ex.Json
{
    /// <summary>
    /// 基础值类型json转换器
    /// (适用于:byte、sbyte、int16、uint16、int32、uint32、int64、uint64、float、double、decimal、bool类型)
    /// </summary>
    public class BaseValueTypeJsonValueConverter : JsonValueConverterAbs
    {
        private readonly static BaseValueTypeJsonValueConverter _default;
        /// <summary>
        /// 默认实例
        /// </summary>
        public static BaseValueTypeJsonValueConverter Default
        {
            get { return _default; }
        }

        static BaseValueTypeJsonValueConverter()
        {
            _default = new BaseValueTypeJsonValueConverter();
        }





        /// <summary>
        /// 构造函数
        /// </summary>
        public BaseValueTypeJsonValueConverter()
            : base(false)
        {

        }





        /// <summary>
        /// 尝试将对象值转换为json值[转换成功返回true,失败返回false]
        /// </summary>
        /// <param name="memberInfo">成员信息</param>
        /// <param name="valueType">值类型</param>
        /// <param name="owner">成员所属对象</param>
        /// <param name="value">属性或字段值</param>
        /// <param name="jsonValue">成员值</param>
        /// <returns>转换成功返回true,失败返回false</returns>
        protected override bool PrimitiveTryConvertTo(MemberInfo memberInfo, Type valueType, object owner, object value, out string jsonValue)
        {
            bool result = true;

            if (value == null)
            {
                if (JsonHelper.AllowNull(valueType))
                {
                    //可空类型,json值为null
                    jsonValue = null;
                }
                else
                {
                    //非可空类型,但是值为null,不符合预期
                    result = false;
                    jsonValue = null;
                }
            }
            else
            {
                jsonValue = value.ToString();
            }

            return result;
        }




        /// <summary>
        /// 尝试将json值转换为对象值[转换成功返回true,失败返回false]
        /// </summary>
        /// <param name="memberInfo">成员信息</param>
        /// <param name="valueType">值类型</param>
        /// <param name="owner">成员所属对象</param>
        /// <param name="jsonValue">json值</param>
        /// <param name="value">对象值</param>
        /// <returns>转换成功返回true,失败返回false</returns>
        protected override bool PrimitiveTryConvertFrom(MemberInfo memberInfo, Type valueType, object owner, string jsonValue, out object value)
        {
            bool result = true;

            if (string.IsNullOrWhiteSpace(jsonValue) || JsonHelper.IsNull(jsonValue))
            {
                if (JsonHelper.AllowNull(valueType))
                {
                    //非可空类型,但是值为null,不符合预期                    
                    value = null;
                }
                else
                {
                    value = null;
                    result = false;
                }
            }
            else
            {
                if (jsonValue[0] == '.')
                {
                    value = ConvertEx.ConvertTo(valueType, $"0{jsonValue}");
                }
                else
                {
                    if (jsonValue[0] == '+')
                    {
                        jsonValue = jsonValue.Trim('+');
                    }

                    if (jsonValue.StartsWith("0x") || jsonValue.StartsWith("0X"))
                    {
                        //十六进制
                        if (string.Equals("x", jsonValue.Trim('0'), StringComparison.OrdinalIgnoreCase))
                        {
                            value = ConvertEx.ConvertTo(valueType, "0");
                        }
                        else
                        {
                            switch (Type.GetTypeCode(valueType))
                            {
                                case TypeCode.SByte:
                                    value = Convert.ToSByte(jsonValue, 16);
                                    break;
                                case TypeCode.Byte:
                                    value = Convert.ToByte(jsonValue, 16);
                                    break;
                                case TypeCode.Int16:
                                    value = Convert.ToInt16(jsonValue, 16);
                                    break;
                                case TypeCode.UInt16:
                                    value = Convert.ToUInt16(jsonValue, 16);
                                    break;
                                case TypeCode.Int32:
                                    value = Convert.ToInt32(jsonValue, 16);
                                    break;
                                case TypeCode.UInt32:
                                    value = Convert.ToUInt32(jsonValue, 16);
                                    break;
                                case TypeCode.Int64:
                                    value = Convert.ToInt64(jsonValue, 16);
                                    break;
                                case TypeCode.UInt64:
                                    value = Convert.ToUInt64(jsonValue, 16);
                                    break;
                                default:
                                    throw new NotSupportedException($"不支持的将值\"{jsonValue}\"转换为数据类型\"{valueType.FullName}\"");
                            }
                        }
                    }
                    else
                    {
                        if (string.Equals(jsonValue, "NaN", StringComparison.OrdinalIgnoreCase))
                        {
                            //非数字
                            switch (Type.GetTypeCode(valueType))
                            {
                                case TypeCode.Single:
                                    value = float.NaN;
                                    break;
                                case TypeCode.Double:
                                    value = double.NaN;
                                    break;
                                default:
                                    throw new NotSupportedException($"不支持的将值\"{jsonValue}\"转换为数据类型\"{valueType.FullName}\"");
                            }
                        }
                        else if (string.Equals(jsonValue, "Infinity", StringComparison.OrdinalIgnoreCase))
                        {
                            //正无穷
                            switch (Type.GetTypeCode(valueType))
                            {
                                case TypeCode.Single:
                                    value = float.PositiveInfinity;
                                    break;
                                case TypeCode.Double:
                                    value = double.PositiveInfinity;
                                    break;
                                default:
                                    throw new NotSupportedException($"不支持的将值\"{jsonValue}\"转换为数据类型\"{valueType.FullName}\"");
                            }
                        }
                        else if (string.Equals(jsonValue, "-Infinity", StringComparison.OrdinalIgnoreCase))
                        {
                            //负无穷
                            switch (Type.GetTypeCode(valueType))
                            {
                                case TypeCode.Single:
                                    value = float.NegativeInfinity;
                                    break;
                                case TypeCode.Double:
                                    value = double.NegativeInfinity;
                                    break;
                                default:
                                    throw new NotSupportedException($"不支持的将值\"{jsonValue}\"转换为数据类型\"{valueType.FullName}\"");
                            }
                        }
                        else
                        {
                            value = ConvertEx.ConvertTo(valueType, jsonValue);
                        }
                    }
                }
                //value = Convert.ChangeType(jsonValue, valueType);
            }

            return result;
        }
    }
}
